package com.unittec.zk.provider.aspect;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.unittec.zk.provider.scope.ThreadLocalScope;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.unittec.zk.provider.ApplicationContextProvider;
import com.unittec.zk.provider.annotation.DataScope;
import com.unittec.zk.provider.service.RootCommonUtils;
import com.unittec.zk.sdk.root.domain.DataScopeBase;

/**
 * 数据过滤处理
 * 
 * @author ruoyi
 */
@Aspect
@Component
public class DataScopeAspect {

    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 部门数据权限
     */
    public static final String DATA_SCOPE_DEPT = "3";

    /**
     * 部门及以下数据权限
     */
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "5";

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.unittec.zk.provider.annotation.DataScope)")
    public void dataScopePointCut() {}

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint point) {
        handleDataScope(point);
    }

    /**
     * 处理数据权限
     * 
     * @param joinPoint
     */
    protected void handleDataScope(final JoinPoint joinPoint) {
        // 获得注解
        DataScope dataScope = getAnnotationLog(joinPoint);
        if (dataScope == null) {
            return;
        }
        // 获取当前用户
        String userId = ThreadLocalScope.getAuthData().getUser();
        // 递归查询当前用户的部门和子部门
        List<String> departList = new ArrayList<>();
        if (StringUtils.isNotBlank(userId)) {
            RootCommonUtils rootCommonUtils = ApplicationContextProvider.getApplicationContext().getBean(RootCommonUtils.class);
            departList = rootCommonUtils.getUserDepartIds(userId, true);
        }
        // 部门数据权限
        dataScopeFilterByDept(joinPoint, dataScope, departList);
    }

    /**
     * 部门数据权限过滤
     * 
     * @param joinPoint
     * @param dataScope
     * @param departList
     */
    public static void dataScopeFilterByDept(JoinPoint joinPoint, DataScope dataScope, List<String> departList) {
        if (departList == null || departList.size() == 0) {
            return;
        }
        List<String> departListNew = new ArrayList<>();
        for (String str : departList) {
            str = "'" + str + "'";
            departListNew.add(str);
        }

        StringBuilder sqlString = new StringBuilder();
        sqlString.append(" AND ");
        if (StringUtils.isNotBlank(dataScope.deptAlias())) {
            sqlString.append(dataScope.deptAlias());
            sqlString.append(".");
        }
        if (StringUtils.isNotBlank(dataScope.columnName())) {
            sqlString.append(dataScope.columnName());
        } else {
            sqlString.append("dept_id");
        }
        sqlString.append(" IN  (" + String.join(",", departListNew) + ") ");

        Object[] args = joinPoint.getArgs();
        if (args[dataScope.paramSort()] instanceof Map) {
            Map paramMap = (Map)args[dataScope.paramSort()];
            paramMap.put("dataScope", sqlString.toString());
        } else {
            DataScopeBase baseEntity = (DataScopeBase)joinPoint.getArgs()[dataScope.paramSort()];
            baseEntity.setDataScope(sqlString.toString());
        }
    }

    /**
     * 是否存在注解，如果存在就获取
     */
    private DataScope getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(DataScope.class);
        }
        return null;
    }

}
